import { readFileSync } from 'fs';
import { isAbsolute } from 'node:path/win32';
import { join } from 'path';
import { writeFileSync } from 'node:fs';
import _ from 'lodash';

//TODO 需要优化该config组件
//TODO 像基本的路径判断, 启用判断等
//TODO 多个翻译源启用只用第一个的翻译源配置
export class Config {
  private static instance: Config | null = null;
  private configPath: string;
  //@ts-ignore
  private configObject: Record<string, any> = {};
  private firstEnabledSource: string | null = null;

  private constructor(configPath: string) {
    this.configPath = this.resolveConfigPath(configPath);
    this.loadConfigSync();
  }

  private resolveConfigPath(path: string): string {
    if (!isAbsolute(path)) {
      return join(process.cwd(), path);
    }
    return path;
  }

  private isConfigFileExist(path: string): boolean {
    try {
      readFileSync(path);
      return true;
    } catch (e) {
      return false;
    }
  }

  private loadConfigSync(): void {
    {
      if (!this.isConfigFileExist(this.configPath)) {
        throw new Error(
          `The required file could not be found, the current file points to the following path: ${this.configPath}`
        );
      }
      this.configObject = JSON.parse(readFileSync(this.configPath).toString());
      for (let key in this.configObject) {
        //判断是否启用该翻译源
        if (this.configObject.hasOwnProperty(key) && this.configObject[key]['enabled']) {
          this[key] = this.configObject[key]; //把配置项挂载到this上
          //判断翻译项是否有多启用,多启用默认使用第一个
          if (this.firstEnabledSource === null) {
            this.firstEnabledSource = key;
          }
        }
      }
      if (this.firstEnabledSource === null) {
        throw new Error(`No translation source is enabled, please check the configuration file`);
      }
    }
  }

  public static getInstance(configPath: string = './configuration.json'): Config {
    if (!Config.instance) {
      Config.instance = new Config(configPath);
    }
    return Config.instance;
  }

  public updateConfig(newConfig: Record<string, any>) {
    try {
      this.configObject = _.merge({}, this.configObject, newConfig);
      writeFileSync(this.configPath, JSON.stringify(this.configObject, null, 2), 'utf-8');
      this.loadConfigSync(); //将单例类配置文件重新加载
    } catch (error) {
      //@ts-ignore
      throw new Error(`Failed to update configuration: ${error.message}`);
    }
  }

  public resetConfig(newConfigPath: string): void {
    newConfigPath = this.resolveConfigPath(newConfigPath);
    if (!this.isConfigFileExist(newConfigPath)) {
      throw new Error(
        `The required file could not be found, the current file points to the following path: ${newConfigPath}`
      );
    }
    try {
      this.configPath = newConfigPath;
      this.loadConfigSync();
    } catch (error) {
      //@ts-ignore
      throw new Error(`Failed to reset configuration`);
    }
  }

  public getConfigObject(): object {
    return this.configObject as object;
  }

  public getFirstEnabledSource(): string | null {
    return this.firstEnabledSource;
  }

  //TODO 开发测试方法,生产版本需删除此方法
  public static resetInstanceStatus(): void {
    Config.instance = null;
  }
}
